/**********************************************************************************************************************
 *
 * Project:    mGameEngine
 * File:       thread.h
 * Author:     karooolek
 * Created on: 2009-01-06
 *
 **********************************************************************************************************************/

#ifndef THREAD_H_
#define THREAD_H_

#include "types.h"
#ifdef WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#else
#include <pthread.h>
#include <unistd.h>
#endif

namespace mGameEngine
{

/**
 * Abstract base class for creating threads in multi-threaded applications.
 * In order to create own thread, you must derive from Thread and
 * override its _run() method.
 */
class Thread
{
protected:
#ifdef WIN32
    /**
     * Thread entry function.
     */
    static DWORD WINAPI _threadEntry(LPVOID);

    /**
     * Thread handle.
     */
    HANDLE _thread;
#else
    /**
     * Thready entry function.
     * @param thread thread to run.
     */
    static void *_threadEntry(void *thread);

    /**
     * Thread handle.
     */
    pthread_t _thread;

    /**
     * Suspension mutex.
     */
    pthread_mutex_t _suspended;
#endif

    /**
     * Stop request.
     */
    volatile bool _stop;

    /**
     * Run thread.
     */
    virtual void _run() = 0;

    /**
     * Sleep (cease execution) for specified time.
     * @param sec sleep time in seconds
     */
    void _sleep(float sec);

public:
    /**
     * Create new thread.
     * New thread doesn't start itself.
     * start() must be called explicitly.
     */
    Thread();

    /**
     * Destroy thread.
     */
    virtual ~Thread();

    /**
     * Start thread execution.
     */
    void start();

    /**
     * Execute thread in current context.
     */
    void exec();

    /**
     * Send stop request to thread.
     */
    void stop();

    /**
     * Terminate thread execution.
     * Dangerous, should be used only in extreme cases!
     */
    void terminate();

    /**
     * Resume thread execution.
     */
    void resume();

    /**
     * Suspend thread execution.
     */
    void suspend();

    /**
     * Join thread.
     * Waits until thread finishes.
     */
    void join() const;
};

}

#endif // THREAD_H_
